import collections
import dataclasses
import datetime
import json
import numpy
import pandas
import pathlib
import matplotlib.axes
import matplotlib.pyplot
from typing import Any, Type, Optional, Union, Callable, Sequence  # , Dict, List, Set, Tuple
import vnpy.tools.database_cta
import vnpy.tools.utility
import vnpy.trader.object
import vnpy.trader.utility
import vnpy_ctastrategy.backtesting
import vnpy_ctastrategy.base
from vnpy.trader.constant import Direction, Exchange, Interval, Offset, Status, Product, OptionType, OrderType


@dataclasses.dataclass
class DrawData:
    """"""
    title: str = None
    xpoints: numpy.ndarray = None
    ypoints: numpy.ndarray = None


@dataclasses.dataclass(frozen=True)
class KeyData:
    """"""
    strategy_name: str = ""  # 交易策略
    interval: Interval = None  # K线周期
    exchange: Exchange = None  # 交易所(self.exchange.value)
    symbol: str = ""  # 代码
    setting: str = ""


def load_once_by_file(
    sqlite_filepath: Union[str, pathlib.Path],
) -> tuple[KeyData, pandas.DataFrame]:
    """"""
    cta_db: vnpy.tools.database_cta.CtaBacktestDatabase = vnpy.tools.database_cta.get_database()
    cta_db.reinitialize(sqlite_filepath=sqlite_filepath)

    ################################################################################

    cta_dump_data: vnpy.tools.database_cta.CtaDumpData = vnpy.tools.database_cta.CtaDumpDataTool.filepath_2_CtaDumpData(filepath=sqlite_filepath)

    ################################################################################

    cta_daily_result_data_list: list[vnpy.tools.database_cta.CtaDailyResultData] = cta_db.load_cta_daily_result_data(
    )

    self_daily_results: dict[datetime.date, vnpy_ctastrategy.backtesting.DailyResult] = {}
    for cta_daily_result_data in cta_daily_result_data_list:
        daily_result: vnpy_ctastrategy.backtesting.DailyResult = cta_daily_result_data.py2DailyResult(py_line=cta_daily_result_data)
        self_daily_results[daily_result.date] = daily_result

    self_daily_results = dict(sorted(self_daily_results.items()))

    # Generate dataframe
    results: collections.defaultdict = collections.defaultdict(list)

    for daily_result in self_daily_results.values():
        for key, value in daily_result.__dict__.items():
            if key == "trades":  # 这个字段在DataFrame里面没有用到,
                continue
            results[key].append(value)

    self_daily_df: Optional[pandas.DataFrame] = pandas.DataFrame.from_dict(results).set_index("date") if results else None

    ################################################################################

    key_data = KeyData(
        strategy_name=cta_dump_data.strategy_name,
        interval=cta_dump_data.interval,
        exchange=cta_dump_data.exchange,
        symbol=cta_dump_data.symbol,
        setting=vnpy.tools.utility.dict2str(setting=cta_dump_data.setting),
    )

    df: pandas.DataFrame = self_daily_df[["net_pnl"]]

    return (key_data, df)


def load_multi_by_file(
    strategy_name: str,
    interval: Interval,
    exchange: Exchange,
    symbol: str,
) -> dict[KeyData, pandas.DataFrame]:
    """"""
    glob_pattern = "{strategy_name}_{interval}_{exchange}_{symbol}_*.db".format(
        strategy_name=strategy_name,
        interval=interval.value,
        exchange=exchange.value,
        symbol=symbol,
    )

    dir_path: pathlib.Path = vnpy.trader.utility.get_folder_path(vnpy.tools.database_cta.CTA_BACKTEST_RESULT_BF_CONT_DBS)

    filepaths: list[pathlib.Path] = [_ for _ in dir_path.glob(glob_pattern) if _.is_file()]

    mapping: dict[KeyData, pandas.DataFrame] = {}

    for filepath in filepaths:
        key_data, df = load_once_by_file(sqlite_filepath=filepath)
        mapping[key_data] = df

    return mapping


def conv_data(
    mapping: dict[KeyData, pandas.DataFrame],
    beg: datetime.date,
    lst: datetime.date,
    capital: int = 1_000_000,
) -> list[DrawData]:
    """"""
    draw_data_s: list[DrawData] = []
    for key_data, df in mapping.items():
        df = df.loc[beg:lst].copy()

        df["balance"] = df["net_pnl"].cumsum() + capital

        setting: dict = json.loads(key_data.setting)

        draw_data = DrawData(
            title=f'{setting["interval"]}_{setting["line_window"]:03d}_{setting["day_trading"]}',
            xpoints=df.index.values,
            ypoints=df["balance"].values,
        )
        draw_data_s.append(draw_data)

    draw_data_s.sort(key=lambda _: _.title)

    return draw_data_s


def show_data(draw_data_s: list[DrawData]):
    """"""
    print("count:", len(draw_data_s))

    fig, axes = matplotlib.pyplot.subplots(nrows=14, ncols=16)
    fig.subplots_adjust(left=0.02, right=0.995, top=0.98, bottom=0.02)
    fig.canvas.manager.window.showMaximized()

    for idx, draw_data in enumerate(draw_data_s):
        row: int = idx // len(axes[0])
        col: int = idx % len(axes[0])

        ax: matplotlib.axes.Axes = axes[row][col]
        ax.set_title(draw_data.title)
        ax.plot(draw_data.xpoints, draw_data.ypoints)
        ax.set_xticks([])  # 取消x轴刻度

    matplotlib.pyplot.show()


if __name__ == "__main__":
    dt1 = datetime.datetime.now()
    mapping: dict[KeyData, pandas.DataFrame] = load_multi_by_file(
        strategy_name="ZxJjxStrategy",
        interval=Interval.MINUTE05,
        exchange=Exchange.SHFE,
        symbol="agL8",
    )
    dt2 = datetime.datetime.now()
    print("load total_seconds:", (dt2 - dt1).total_seconds())

    draw_data_s: list[DrawData] = conv_data(
        mapping=mapping,
        beg=datetime.date(year=2020, month=1, day=1),
        lst=datetime.date(year=2025, month=1, day=1),
    )

    show_data(draw_data_s=draw_data_s)
